/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package sessions;

import entities.Album;
import entities.Artist;
import entities.Genre;
import entities.Music;
import init.Config;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.ejb.EJB;
import javax.ejb.LocalBean;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import org.jaudiotagger.audio.AudioFile;
import org.jaudiotagger.audio.AudioFileIO;
import org.jaudiotagger.audio.exceptions.CannotReadException;
import org.jaudiotagger.audio.exceptions.InvalidAudioFrameException;
import org.jaudiotagger.audio.exceptions.ReadOnlyFileException;
import org.jaudiotagger.tag.FieldKey;
import org.jaudiotagger.tag.Tag;
import org.jaudiotagger.tag.TagException;
import org.jaudiotagger.tag.reference.GenreTypes;
import util.FileDiscoveryUtil;

/**
 *
 * @author Antoine Boulinguez et Shyn-Yuan Cheng
 */
@Stateless
@LocalBean
public class MusicManager {

    @EJB
    private GenreManager genreManager;
    @EJB
    private AlbumManager albumManager;
    @EJB
    private ArtistManager artistManager;
    @PersistenceContext(unitName = "ProjetStreamingBoulinguezCheng-ejbPU")
    private EntityManager em;

    // Create a music
    public Music createMusic(Album album, String title, Artist artist, Genre genre, Date releaseDate, int totalTime, String filePath) {
        Music music = new Music(title, artist, genre, releaseDate, totalTime, filePath);
        music.setCoverImage(album.getCoverImage());
        music.setAlbum(album);
        persist(music);

        album.addMusic(music);
        //album.addGenre(genre);
        update(album);

        artist.addGenre(genre);
        artist.addMusic(music);
        update(artist);

        return music;
    }

    // Get all music
    public List<Music> getAllMusics() {
        Query query = em.createNamedQuery("Music.findAll");
        return query.getResultList();
    }

    // Get a music by it id
    public Music getMusic(Long id) {
        Query query = em.createNamedQuery("Music.findById");
        query.setParameter("id", id);

        try {
            Object result = query.getSingleResult();
            return (Music) result;
        } catch (NoResultException e) {
            return null;
        }
    }
    
    // Get musics by genre
    public List<Music> getMusics(Genre genre) {
        Query query = em.createNamedQuery("Music.findByGenre");
        query.setParameter("genre", genre);
        
        return query.getResultList();
    }

    // Scan a directory to import musics into the DB
    public void initDBWithMp3s() {
        // Get MP3 files from directory
        String absoluteMp3DirPath = Config.SERVER_WEB_DIR + File.separator + Config.MP3_BASE_DIRECTORY;
        File baseFile = new File(absoluteMp3DirPath);
        List<File> fileList = FileDiscoveryUtil.listMp3sFrom(baseFile);

        System.out.println("Nombre de fichiers : " + fileList.size());

        // For each file, read ID3 tags insert the song into the database
        for (File f : fileList) {
            // The path must be a valid relative URI (without special chars)
            String filePath = f.getAbsolutePath().substring(Config.SERVER_WEB_DIR.length() + 1, f.getAbsolutePath().length());
            filePath = filePath.replaceAll("\\\\", "/");
            try {
                URI uri = new URI(null, null, filePath, null);
                filePath = uri.toString();
            } catch (URISyntaxException ex) {
                Logger.getLogger(MusicManager.class.getName()).log(Level.SEVERE, null, ex);
            }
            System.out.println("# Traitement du MP3 : " + filePath);

            AudioFile af = null;
            try {
                af = AudioFileIO.read(f);
            } catch (CannotReadException ex) {
                Logger.getLogger(MusicManager.class.getName()).log(Level.SEVERE, null, ex);
            } catch (IOException ex) {
                Logger.getLogger(MusicManager.class.getName()).log(Level.SEVERE, null, ex);
            } catch (TagException ex) {
                Logger.getLogger(MusicManager.class.getName()).log(Level.SEVERE, null, ex);
            } catch (ReadOnlyFileException ex) {
                Logger.getLogger(MusicManager.class.getName()).log(Level.SEVERE, null, ex);
            } catch (InvalidAudioFrameException ex) {
                Logger.getLogger(MusicManager.class.getName()).log(Level.SEVERE, null, ex);
            }

            if (af != null) {
                Tag tag = af.getTag();

                if (tag != null) {
                    // Get tag values
                    String title = tag.getFirst(FieldKey.TITLE);
                    String artistName = tag.getFirst(FieldKey.ARTIST);
                    String genreStr = tag.getFirst(FieldKey.GENRE);
                    String year = tag.getFirst(FieldKey.YEAR);
                    int totalTime = af.getAudioHeader().getTrackLength();
                    String albumStr = tag.getFirst(FieldKey.ALBUM);

                    // If no title tag, replace it with the file name
                    if (title == null || title.equals("")) {
                        title = f.getName();
                    }

                    // Get the date object
                    Date releaseDate = null;
                    if (year != null && !year.equals("")) {
                        Calendar cal = Calendar.getInstance();
                        cal.set(Integer.parseInt(year), 1, 1);
                        releaseDate = cal.getTime();
                    }

                    // Get genre in string format from it id3 code (ex : 17 = Rock)
                    GenreTypes genreTypes = GenreTypes.getInstanceOf();
                    Integer id3GenreId = genreTypes.getIdForName(genreStr);
                    String genreStr2 = "Other";
                    if (id3GenreId != null) {
                        genreStr2 = genreTypes.getValueForId(id3GenreId);
                    }

                    // Create artist, album and the kind of music if they don't exist
                    Artist artist = artistManager.createArtist(artistName);
                    Album album = albumManager.createAlbum(albumStr, artist, releaseDate);
                    Genre genre = genreManager.createGenre(genreStr2);

                    // Create the music
                    createMusic(album, title, artist, genre, releaseDate, totalTime, filePath);
                }
            }
        }
    }

    public void incSongPlayCount(Long songId) {
        Music music = getMusic(songId);
        music.incPlayCount();
        update(music);
    }

    public void update(Object object) {
        em.merge(object);
    }

    public void persist(Object object) {
        em.persist(object);
    }
}
